home *** CD-ROM | disk | FTP | other *** search
/ BCI NET 2 / BCI NET 2.iso / archives / programming / asm / adisv1_3.lha / src / jmptab.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-09-24  |  5.8 KB  |  227 lines

  1. /*
  2.  * Change history
  3.  * $Log $
  4.  */
  5.  
  6. #include <exec/types.h>
  7. #include <string.h>
  8. #include "defs.h"
  9.  
  10. static char rcsid [] = "$Id: jmptab.c,v 3.0 93/09/24 17:54:04 Martin_Apel Exp $";
  11.  
  12. /*
  13.  * This list handles all references made through PC-relative with index
  14.  * addressing modes. It contains all data that's important for disassembling
  15.  * jump tables.
  16.  * Idea for handling jump tables:
  17.  * The instruction stream that handles the calling of the corresponding
  18.  * routine cannot be jmuped into in the middle, i.e. the last reference
  19.  * to the current code hunk before the JMP at the end of that instruction
  20.  * stream is the loading of the start address of the jump table and it's
  21.  * guaranteed that those two instructions will be disassembled nearly
  22.  * consecutively.
  23.  * Implementation:
  24.  * Introduce a static variable in decode_ea, which always stores the last
  25.  * reference to the current code hunk (PC rel or relocated). When the JMP
  26.  * instruction is disassembled it uses this information and enters the
  27.  * jump table into the list.
  28.  */
  29.  
  30. struct jmptab_descr
  31.   {
  32.   struct jmptab_descr *Next;
  33.   ULONG Start,
  34.         End,
  35.         ReferencingInstr,
  36.         JmpOffset;
  37.   BOOL  ReallyJmpTable;              /* for backtracking */
  38.   BOOL  AllDone;
  39.   };
  40.  
  41. PRIVATE struct jmptab_descr *JmpTables = NULL;
  42. PRIVATE last_code_ref_from_jmptab = UNSET;
  43.  
  44. /*********************************************************************/
  45.  
  46. void free_jmptab_list ()
  47.  
  48. {
  49. struct jmptab_descr *tmp;
  50.  
  51. while (JmpTables != NULL)
  52.   {
  53.   tmp = JmpTables->Next;
  54.   release_mem (JmpTables);
  55.   JmpTables = tmp;
  56.   }
  57. }
  58.  
  59. /*********************************************************************/
  60.  
  61. void enter_jmptab (ULONG start, ULONG jmp_offset)
  62.  
  63. {
  64. struct jmptab_descr *tmp;
  65. ULONG ref;
  66. short offset;
  67.  
  68. /* Search if this jump-table has already been entered */
  69. for (tmp = JmpTables; tmp != NULL; tmp = tmp->Next)
  70.   {
  71.   if (tmp->ReferencingInstr == current_address)
  72.     {
  73. #ifdef DEBUG    
  74.     fprintf (stderr, "enter_jmptab: JumpTable multiply added\n");
  75. #endif
  76.     return;
  77.     }
  78.   }
  79.  
  80. /* Jump tables either lie directly after the JMP instruction or
  81.  * before it.
  82.  */
  83.  
  84. offset = *(code + (start - current_address) / 2);
  85. ref = current_address + offset + jmp_offset + 2;
  86.  
  87. if (((start != current_address + 4) && (start >= current_address)) ||
  88.     ODD (offset) || (ref < first_address) || (ref >= last_address))
  89.   return;
  90.  
  91. /* To prevent ADis to backtrack completely in case of wrongly recognized
  92.  * jump table, I do a save flags before entering the new jump table
  93.  */
  94.  
  95. save_flags ();
  96.  
  97. /* Compute the first location the jump-table points to, and enter
  98.  * that into the symbol-table as a code reference.
  99.  */
  100.  
  101. enter_ref (ref, NULL, ACC_CODE);
  102. last_code_ref_from_jmptab = start;
  103.  
  104. /* Didn't find an entry, make a new one */
  105. tmp = get_mem (sizeof (struct jmptab_descr));
  106. tmp->Start = start;
  107. tmp->End = start + 2;
  108. tmp->JmpOffset = jmp_offset;
  109. tmp->ReferencingInstr = current_address;
  110. tmp->ReallyJmpTable = TRUE;
  111. tmp->AllDone = FALSE;
  112. tmp->Next = JmpTables;
  113. JmpTables = tmp;
  114. }
  115.  
  116. /*********************************************************************/
  117.  
  118. BOOL next_code_ref_from_jmptab (UWORD *seg)
  119.  
  120. {
  121. /* Searches for the next jump table that has not been fully disassembled.
  122.  * It enters the corresponding location into the symbol table as a code
  123.  * reference. If it doesn't find another entry it returns FALSE.
  124.  */
  125.  
  126. struct jmptab_descr *tmp;
  127. ULONG ref;
  128. short offset;
  129.  
  130. for (tmp = JmpTables; tmp != NULL; tmp = tmp->Next)
  131.   {
  132.   if (tmp->ReallyJmpTable && !tmp->AllDone &&
  133.       tmp->Start != UNSET && tmp->End != UNSET && tmp->JmpOffset != UNSET)
  134.     {
  135.     if (IS_PROBABLE (tmp->End))
  136.       tmp->AllDone = TRUE;
  137.     else
  138.       {
  139.       offset = (short)*(seg + (tmp->End - first_address) / 2);
  140.       ref = tmp->ReferencingInstr + offset + tmp->JmpOffset + 2;
  141.       if (ODD (offset) || ref < first_address || ref >= last_address)
  142.         {
  143.         tmp->AllDone = TRUE;
  144.         continue;
  145.         }
  146.       enter_ref (ref, NULL, ACC_CODE);
  147.       last_code_ref_from_jmptab = tmp->End;
  148.       tmp->End += 2;
  149.       return (TRUE);
  150.       }
  151.     }
  152.   }
  153. return (FALSE);
  154. }
  155.  
  156. /*********************************************************************/
  157.  
  158. BOOL invalidate_last_jmptab_entry ()
  159.  
  160. {
  161. /* The last code reference from a jump table has led to an error.
  162.  * Mark it as data and mark the jump table as fully disassembled.
  163.  */
  164.  
  165. struct jmptab_descr *tmp;
  166.  
  167. for (tmp = JmpTables; tmp != NULL; tmp = tmp->Next)
  168.   {
  169.   if (last_code_ref_from_jmptab == tmp->End - 2 && !tmp->AllDone)
  170.     {
  171.     tmp->End -= 2;
  172.     tmp->AllDone = TRUE;
  173.     if (last_code_ref_from_jmptab == tmp->Start)
  174.       {
  175.       last_code_ref_from_jmptab = UNSET;
  176.       tmp->ReallyJmpTable = FALSE;
  177.       }
  178.     return (TRUE);
  179.     }
  180.   }
  181. return (FALSE);
  182. }
  183.  
  184. /**************************************************************************/
  185.  
  186. BOOL find_jmptab_and_print (char *string)
  187.  
  188. /* Tests if current_address lies within a jump-table. If it does, it 
  189.  * prints a label description to string.
  190.  * When this routine is called, code points to data at current_address.
  191.  */
  192. {
  193. struct jmptab_descr *tmp;
  194.  
  195. for (tmp = JmpTables; tmp != NULL; tmp = tmp->Next)
  196.   {
  197.   if (tmp->Start != UNSET && tmp->End != UNSET && tmp->JmpOffset != UNSET &&
  198.       current_address >= tmp->Start && current_address < tmp->End)
  199.     {
  200.     gen_label (string, tmp->ReferencingInstr + (short)*code + 
  201.                tmp->JmpOffset + 2, USE_LABEL);
  202.     strcat (string, "-");
  203.     gen_label (string + strlen (string), tmp->ReferencingInstr, USE_LABEL);
  204.     strcat (string, "-");
  205.     format_d (string + strlen (string), 
  206.               (short)(2L + tmp->JmpOffset), USE_SIGN);
  207.     return (TRUE);
  208.     }
  209.   }
  210. return (FALSE);
  211. }
  212.  
  213. /**************************************************************************/
  214.  
  215. #ifdef DEBUG
  216.  
  217. void print_jmptab_list ()
  218.  
  219. {
  220. struct jmptab_descr *tmp;
  221.  
  222. for (tmp = JmpTables; tmp != 0; tmp = tmp->Next)
  223.   printf ("Jump table at %lx ref'd from %lx\n", tmp->Start, 
  224.           tmp->ReferencingInstr);
  225. }
  226. #endif
  227.